package com.gopay.bis.service.bank.task;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import com.gopay.remote.cashier.bis.CashierBgNotifyRemoteService;
import com.gopay.remote.cps.bis.ErrOrderRecordRemoteService;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import com.gopay.bis.common.util.SendSmsUtils;
import com.gopay.bis.manager.bank.BankOrderManager;
import com.gopay.common.Result;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.bank.QueryNeedCertConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.HttpTransport;
import com.gopay.common.util.RSAEncoderUtil;
import com.gopay.common.util.spring.SpringContextUtil;
import com.gopay.remote.bank.ExPayInteractRemoteService;

public class AdPayTaskThread implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(AdPayTaskThread.class);

    private ExPayBaseMessage exPayMsg;

    private ExPayInteractRemoteService exPaybankInteractService;

    private HttpTransport notifyCashier;

    private CashierBgNotifyRemoteService cashierBgNotifyRemoteService;

    private BankOrderManager bankOrderManager;

    private CpsGeneralMainOrderQueryManager mainOrderQuery;
    
    protected ErrOrderRecordRemoteService errOrderRecordService;

    @Resource(name = "smsConfig")
    private Map<String, String> smsConfig;

    public AdPayTaskThread(ExPayBaseMessage exPayMsg, ExPayInteractRemoteService exPaybankInteractService,ErrOrderRecordRemoteService errOrderRecordService,CashierBgNotifyRemoteService cashierBgNotifyRemoteService) {
        this.exPaybankInteractService = exPaybankInteractService;
        this.errOrderRecordService = errOrderRecordService;
        this.exPayMsg = exPayMsg;
        this.cashierBgNotifyRemoteService = cashierBgNotifyRemoteService;
    }

    public void run() {
        try {
            // 日志输出隐藏信用卡cvv2
            ExPayBaseMessage logData = getPrintMsg(exPayMsg);
            logger.error("AdPayTaskThread process order:" + ToStringBuilder.reflectionToString(logData));

            Map<String, String> param = new HashMap<String, String>();

            // 调用是否需要签约接口
            Result needCertResult = exPaybankInteractService.queryNeedCert(exPayMsg);
            if (!needCertResult.isSuccess()) {
                param.put("orderId", exPayMsg.getOrderId());
                param.put("amt", exPayMsg.getAmount().toString());
                param.put("cardType", "Unknown");
                param.put("notifyNum", "1");
                param.put("payStatus", "01");
                param.put("retCode", "01");
                param.put("retMsg", "验签失败");
                param.put("signData", "");
                param.put("isFront", "false");
                param.put("sign", signRes(param));
                cashierBgNotifyRemoteService.callBgNotify(param);
                return;
            } else if (QueryNeedCertConstants.QUERY_RESULT_NEED.equals(needCertResult.getModel("NeedMark"))) {
                Result certResult = exPaybankInteractService.certification(exPayMsg);
                if (certResult.isSuccess() && (boolean) certResult.getModel("flag")) {
                    logger.error("AdPayTaskThread certification success !");
                } else {
                    param.put("orderId", exPayMsg.getOrderId());
                    param.put("amt", exPayMsg.getAmount().toString());
                    param.put("cardType", "Unknown");
                    param.put("notifyNum", "1");
                    param.put("payStatus", "01");
                    param.put("retCode", "01");
                    param.put("retMsg", "验签失败");
                    param.put("signData", "");
                    param.put("isFront", "false");
                    param.put("sign", signRes(param));
                    cashierBgNotifyRemoteService.callBgNotify(param);
                    return;
                }
            }

            Result result = exPaybankInteractService.payment(exPayMsg);
            if (!result.isSuccess()) {// 处理失败
                logger.error("AdPayTaskThread Exception:" + result.getResultCode());
            }

            if (!result.isSuccess()) {
                // 操作异常
                param.put("orderId", exPayMsg.getOrderId());
                param.put("amt", exPayMsg.getAmount().toString());
                param.put("cardType", "Unknown");
                param.put("notifyNum", "1");
                param.put("payStatus", "01");
                param.put("retCode", "01");
                param.put("retMsg", "验签失败");
                param.put("signData", "");
                param.put("isFront", "false");

                bankOrderManager.updateBackVerifyFail(exPayMsg.getOrderId());
                logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
                        + "】失败，bis_bank_main_order表更新失败状态");
                param.put("sign", signRes(param));
                cashierBgNotifyRemoteService.callBgNotify(param);
                return;
            }

            // 测试银行报文加密并组装
            if (exPayMsg.getBank().equals("TBANK")) {
                if ((boolean) result.getModel("flag")) {
                    // 验签成功入账
                    param.put("orderId", exPayMsg.getOrderId());
                    param.put("amt", exPayMsg.getAmount().toString());
                    param.put("cardType", "Unknown");
                    param.put("notifyNum", "1");
                    param.put("payStatus", "00");
                    param.put("retCode", "00");
                    param.put("retMsg", "验签成功");
                    param.put("signData", "");
                    param.put("isFront", "false");
                } else {
                    // 失败
                    param.put("orderId", exPayMsg.getOrderId());
                    param.put("amt", exPayMsg.getAmount().toString());
                    param.put("cardType", "Unknown");
                    param.put("notifyNum", "1");
                    param.put("payStatus", "01");
                    param.put("retCode", "01");
                    param.put("retMsg", "验签失败");
                    param.put("signData", "");
                    param.put("isFront", "false");
                }
                param.put("sign", signRes(param));
                cashierBgNotifyRemoteService.callBgNotify(param);
                return;
            }
            
            BankOrder bankOrder = null;
            bankOrder = bankOrderManager.getBankOrderById(exPayMsg.getBankOrderId());
            if (bankOrder == null) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E5041);
            }

            if (BankConstants.BANK_LOGO_UMPAY.equals(exPayMsg.getOutStlmCd())
                    || BankConstants.BANK_LOGO_YEEPAY.equals(exPayMsg.getOutStlmCd())
                    || BankConstants.BANK_LOGO_YSPAY.equals(exPayMsg.getOutStlmCd())) {
                if ((boolean) result.getModel("flag")) {
                    // 同步返回成功不通知cashier,等待银行回调
                    logger.error(exPayMsg.getOutStlmCd() + " 同步返回成功不通知cashier等待银行回调, AdPayTaskThread返回处理结果："
                            + ToStringBuilder.reflectionToString(result));
                } else {
                	// 快捷交易同步返回失败通知cashier add by zhengxue 20170313
                    String retMsg = (String) result.getModel("retMsg");
                    param.put("orderId", exPayMsg.getOrderId());
                    param.put("amt", exPayMsg.getAmount().toString());
                    param.put("cardType", "Unknown");
                    param.put("notifyNum", "1");
                    param.put("payStatus", "01");
                    param.put("retCode", "01");
                    param.put("retMsg", retMsg);
                    param.put("signData", "");
                    param.put("isFront", "false");
                    
                    bankOrder.setOrderStatus(BankOrderStatus.ORDER_FAIL);
                    bankOrder.setBankRespCode(result.getBankRetCode());//add by liuyu, 20170802, 快捷API失败通知
                    bankOrderManager.updateBankOrder(bankOrder);
                    logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
                            + "】失败，bis_bank_main_order表更新失败状态");
                    
                    //快捷支付订单处理银行返回失败时， 记录银行响应的错误码和错误描述 add by liuyong 20170216
                    errOrderRecordService.saveOrderErrorMsg(exPayMsg.getOrderId(),result.getResultCode(),retMsg);
                    logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
                            + "】失败，银行返回错误码和错误信息为【"+result.getResultCode()+"==="+retMsg+"】");
                    param.put("sign", signRes(param));
                    /*notifyCashier.submit(param);*/ //生产优化10期 lx 2017-9-30 16:23:37
                    cashierBgNotifyRemoteService.callBgNotify(param);
                	
//                	//----------
//                    bankOrderManager.updateBackVerifyFail(exPayMsg.getOrderId());
//                    logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
//                            + "】失败，bis_bank_main_order表更新失败状态");
                }
            } else {
            	
            	// 是否已通知Cashier
                boolean notifyCashierFlag = false;
				param = (Map<String, String>) result.getModel("isNotifyCashier");
				logger.error("AdPayTaskThread adpay resmsg: " + LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(exPayMsg)));
                if ((Boolean) result.getDefaultModel()) {
                    String retMsg = param.get("retMsg"); // 订单信息描述
                    if (result.isOrderStatus()) {
                        // 支付成功
                        String amt = (String) param.get("amt"); // 银行返回交易金额
                        if (bankOrder.getSendBankAmt() != null
                                && bankOrder.getSendBankAmt().compareTo(new BigDecimal(amt)) != 0) {
                            // 银行返回金额与平台上送金额不符
                            bankOrderManager.updateAmountError(param.get("orderId"));
                            logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【"+param.get("orderId")+"】金额比对异常");
                            SendSmsUtils.sendSmsErr(smsConfig.get("switch"), smsConfig.get("mobile"),"注意!!!订单金额不一致,银行:"+exPayMsg.getOutStlmCd()+"orderId:"+param.get("orderId"));
                            return;
                        }
                        bankOrderManager.updateBackSuccess(param.get("orderId"));
                        logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + param.get("orderId")
                                + "】支付成功，bis_bank_main_order表更新成功状态");

                        param.put("sign", signRes(param));
                        logger.error("bis adpay notify cashier: " + param);
                        notifyCashierFlag = true;
                        cashierBgNotifyRemoteService.callBgNotify(param);
                    } else if (result.isOrderFail()) {
                        // 订单明确返回支付失败
                        bankOrder.setOrderStatus(BankOrderStatus.ORDER_FAIL);
                        bankOrder.setBankRespCode(result.getBankRetCode());//add by liuyu, 20170802, 快捷API失败通知
                        bankOrderManager.updateBankOrder(bankOrder);
                        logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + param.get("orderId")
                                + "】支付失败");
                        
                        //快捷支付订单处理银行返回失败时， 记录银行响应的错误码和错误描述 add by liuyong 20170216
                        errOrderRecordService.saveOrderErrorMsg(exPayMsg.getOrderId(),result.getResultCode(),retMsg);
                        logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
                                + "】失败，银行返回错误码和错误信息为【"+result.getResultCode()+"==="+retMsg+"】");
                        param.put("sign", signRes(param));
                        logger.error("bis adpay notify cashier: " + param);
                        notifyCashierFlag = true;
                        /*notifyCashier.submit(param);*/ //生产优化10期 lx 2017-9-30 16:23:37
                        cashierBgNotifyRemoteService.callBgNotify(param);
                    } else {
                        //快捷支付订单处理银行返回失败时， 记录银行响应的错误码和错误描述 add by liuyong 20170216
                        errOrderRecordService.saveOrderErrorMsg(exPayMsg.getOrderId(),result.getResultCode(),retMsg);
                        logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
                                + "】失败，银行返回错误码和错误信息为【"+result.getResultCode()+"==="+retMsg+"】");
                        logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
                                + "】验签成功订单未成功");
                    }
                } else {
                    bankOrder.setBankRespCode(result.getBankRetCode());//add by liuyu, 20170802, 快捷API失败通知
                    bankOrderManager.updateBankOrder(bankOrder);
                    bankOrderManager.updateBackVerifyFail(exPayMsg.getOrderId());
                    logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
                            + "】验签失败，bis_bank_main_order表更新失败状态");
                }

                /**** 快捷支付订单处理银行返回失败时， 记录银行响应的错误码到银行订单 add by sh.jiao 20170804 start****/
                if(result != null && !notifyCashierFlag
                        && result.isSuccess() && result.isOrderStatus() == false
                        && result.getBankRetCode() != null  && !"".equals(result.getBankRetCode())) {
                    logger.error("发送失败通知。。。"+bankOrder);
                    bankOrder.setBankRespCode(result.getBankRetCode());
                    bankOrderManager.updateBankOrder(bankOrder);
                    //处理银行返回金额为空的情况
                    String amt = param.get("amt");
                    logger.error("AMT:"+amt);
                    if((amt == null || "".equals(amt)) && bankOrder.getSendBankAmt() != null) {
                        param.put("amt",bankOrder.getSendBankAmt().toString());
                    }
                    param.put("sign", signRes(param));
                    logger.error("bis adpay notify cashier: " + param);
                    /*notifyCashier.submit(param);*/ //生产优化10期 lx 2017-9-30 16:23:37
                    cashierBgNotifyRemoteService.callBgNotify(param);
                }
                /**** 快捷支付订单处理银行返回失败时， 记录银行响应的错误码到银行订单 add by sh.jiao 20170804 end****/
            	
            
//                param = (Map<String, String>) result.getModel("isNotifyCashier");
//                // ExPayBaseMessage retExPayMsg = (ExPayBaseMessage)
//                // result.get("res");
//                logger.error("AdPayTaskThread pay resmsg: " + ToStringBuilder.reflectionToString(exPayMsg));
//                if ((Boolean) result.getDefaultModel()) {
//                    // 支付成功
//                    if (result.isOrderStatus()) {
//                        BankOrder bankOrder = null;
//                        bankOrder = bankOrderManager.getBankOrderById(exPayMsg.getBankOrderId());
//                        if (bankOrder == null) {
//                            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5041);
//                        }
//                        String amt = (String) param.get("amt"); // 银行返回交易金额
//                        if (bankOrder.getSendBankAmt() != null
//                                && bankOrder.getSendBankAmt().compareTo(new BigDecimal(amt)) != 0) {
//                            // 银行返回金额与平台上送金额不符
//                            bankOrderManager.updateAmountError(param.get("orderId"));
//                            logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【"
//                                    + param.get("orderId") + "】金额比对异常");
//                            SendSmsUtils.sendSmsErr(smsConfig.get("switch"), smsConfig.get("mobile"),
//                                    "注意!!!订单金额不一致,银行:" + exPayMsg.getOutStlmCd() + "orderId:" + param.get("orderId"));
//                            return;
//                        }
//                        bankOrderManager.updateBackSuccess(param.get("orderId"));
//                        logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + param.get("orderId")
//                                + "】支付成功，bis_bank_main_order表更新成功状态");
//                        param.put("sign", signRes(param));
//                        logger.error("bis expay notify cashier: " + param);
//                        /*notifyCashier.submit(param);*/ //生产优化10期 lx 2017-9-30 16:23:37
//                        cashierBgNotifyRemoteService.callBgNotify(param);
//                    } else {
//                        logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + param.get("orderId")
//                                + "】验签成功订单未成功");
//                    }
//                } else {
//                    bankOrderManager.updateBackVerifyFail(exPayMsg.getOrderId());
//                    logger.error(exPayMsg.getOutStlmCd() + " AdPayTaskThread返回处理结果：国付宝订单号【" + exPayMsg.getOrderId()
//                            + "】验签失败，bis_bank_main_order表更新失败状态");
//                }
               
            }
        } catch (Exception e) {
            logger.error(exPayMsg.getOrderId() + " AdPayTaskThread error", e);
        }

    }

    /**
     * 快捷对象输出，隐藏信用卡cvv2
     * 
     * @param baseMsg
     * @return
     */
    private ExPayBaseMessage getPrintMsg(ExPayBaseMessage baseMsg) {
        ExPayBaseMessage logData = new ExPayBaseMessage();
        BeanUtils.copyProperties(baseMsg, logData);
        if (logData.getCvv2() == null || "".equals(logData.getCvv2())) {
            //
        } else {
            logData.setCvv2("***");
        }
        return logData;
    }

    /**
     * 通知cashier签名
     * 
     * @param res
     * @return
     */
    public String signRes(Map res) {
        StringBuffer sign = new StringBuffer();
        String orderId = (String) res.get("orderId");
        String amt = (String) res.get("amt");
        String retCode = (String) res.get("retCode");
        String retMsg = (String) res.get("retMsg");
        String payStatus = (String) res.get("payStatus");
        String notifyNum = (String) res.get("notifyNum");
        String cardType = (String) res.get("cardType");
        sign.append(orderId).append("|");
        sign.append(amt).append("|");
        sign.append(retCode).append("|");
        sign.append(retMsg).append("|");
        sign.append(payStatus).append("|");
        sign.append(notifyNum).append("|");
        sign.append(cardType);
        logger.error("bis expay通知cashier签名明文: " + sign.toString());
        try {
            return RSAEncoderUtil.sign(sign.toString());
        } catch (Exception e) {
            logger.error("bis expay通知cashier签名异常", e);
        }
        return "";
    }

    public ExPayBaseMessage getExPayMsg() {
        return exPayMsg;
    }

    public void setExPayMsg(ExPayBaseMessage exPayMsg) {
        this.exPayMsg = exPayMsg;
    }

    public HttpTransport getNotifyCashier() {
        return notifyCashier;
    }

    public void setNotifyCashier(HttpTransport notifyCashier) {
        this.notifyCashier = notifyCashier;
    }

    public BankOrderManager getBankOrderManager() {
        return bankOrderManager;
    }

    public void setBankOrderManager(BankOrderManager bankOrderManager) {
        this.bankOrderManager = bankOrderManager;
    }

    public ExPayInteractRemoteService getExPaybankInteractService() {
        return exPaybankInteractService;
    }

    public void setExPaybankInteractService(ExPayInteractRemoteService exPaybankInteractService) {
        this.exPaybankInteractService = exPaybankInteractService;
    }

    public Map<String, String> getSmsConfig() {
        return smsConfig;
    }

    public void setSmsConfig(Map<String, String> smsConfig) {
        this.smsConfig = smsConfig;
    }

    public CpsGeneralMainOrderQueryManager getMainOrderQuery() {
        return mainOrderQuery;
    }

    public void setMainOrderQuery(CpsGeneralMainOrderQueryManager mainOrderQuery) {
        this.mainOrderQuery = mainOrderQuery;
    }

    public CashierBgNotifyRemoteService getCashierBgNotifyRemoteService() {
        return cashierBgNotifyRemoteService;
    }

    public void setCashierBgNotifyRemoteService(CashierBgNotifyRemoteService cashierBgNotifyRemoteService) {
        this.cashierBgNotifyRemoteService = cashierBgNotifyRemoteService;
    }
}
